﻿
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;


namespace BoilenEditor.Primitives {

    [DebuggerDisplay( "MatchPair: Value={Value}, Result={Result}" )]
    public sealed class MatchPair {

        private KeyValuePair<Type, object> convertedValue_;
        private KeyValuePair<Type, object> convertedResult_;


        public object Value { get; set; }

        public object Result { get; set; }


        public object GetConvertedValue( object value ) {
            Type valueType = value.GetValueOrDefault( v => v.GetType( ), typeof( object ) );
            return Convert( valueType, this.Value, ref this.convertedValue_ );
        }

        public object GetConvertedResult( Type resultType ) {
            return Convert( resultType, this.Result, ref this.convertedResult_ );
        }


        private static object Convert( Type type, object original, ref KeyValuePair<Type, object> converted ) {
            if( type != converted.Key ) {
                object convertedValue;
                if( type.IsEnum && original is string ) {
                    convertedValue = Enum.Parse( type, (string)original, true );
                }
                else {
                    TypeConverter typeConverter =
                        type.GetCustomAttribute<TypeConverterAttribute>( )
                            .GetValueOrDefault( attribute => Type.GetType( attribute.ConverterTypeName, false, true ), null )
                            .GetValueOrDefault( converterType => (TypeConverter)Activator.CreateInstance( converterType ), null );

                    if( typeConverter.HasValue( ) && typeConverter.CanConvertFrom( original.GetType( ) ) )
                        convertedValue = typeConverter.ConvertFrom( original );
                    else
                        convertedValue = System.Convert.ChangeType( original, type );
                }

                converted = new KeyValuePair<Type, object>( type, convertedValue );
            }

            return converted.Value;
        }

    }

}
